﻿using NeXus.BIMBase.Core;
using NeXus.BIMBase.Data;
using NeXus.p3d;
using System;
using System.Collections.Generic;

namespace checc_baseTools
{
    public class Helper
    {

        /// <summary>
        /// 计算延长点
        /// </summary>
        /// <param name="M">原点</param>
        /// <param name="N">指向点</param>
        /// <param name="LL">指定延长的长度</param>
        /// <returns></returns>
        public static GePoint3d Extend_or_Contract(GePoint3d pointA, GePoint3d pointB, double Length)
        {
            GeVec3d ab = GeVec3d.createByStartEnd(pointA, pointB);
            //长度*AB的单位向量 单位向量 = 向量 / 向量的模 
            GeVec3d normalize = GeVec3d.createByStartEndNormalize(pointA, pointB);
            double UnitVector_X = Length * normalize.x;
            double UnitVector_Y = Length * normalize.y;
            //double UnitVector_Z = Length * normalize.z;
            //向量AL的L点的坐标
            double NewPoint_X = pointA.x + UnitVector_X;
            double NewPoint_Y = pointA.y + UnitVector_Y;
            //double NewPoint_Z = pointA.z + UnitVector_Z;
            //Console.WriteLine("该点的坐标是:<" + NewPoint_X + "," + NewPoint_Y + ">");
            GePoint3d point = new GePoint3d(NewPoint_X, NewPoint_Y, 0/*NewPoint_Z*/);
            return point;
        }
        /// <summary>
        /// 以圆心绕z轴逆时针旋转，根据长度收缩
        /// </summary>
        /// <param name="pointA">圆心</param>
        /// <param name="pointB">终点</param>
        /// <param name="length">长度</param>
        /// <param name="angle">角度</param>
        /// <returns>收缩后的点</returns>
        public static GePoint3d Rotation(GePoint3d center, GePoint3d pointB, double length, double angle)
        {
            GeVec3d vector = GeVec3d.createByStartEnd(center, pointB);
            double num = System.Math.Cos(System.Math.PI / 180.0 * angle) * vector.x - System.Math.Sin(System.Math.PI / 180.0 * angle) * vector.y;
            double num2 = System.Math.Sin(System.Math.PI / 180.0 * angle) * vector.x + System.Math.Cos(System.Math.PI / 180.0 * angle) * vector.y;
            double a = vector.normalize();
            double num3 = length * (num / a);
            double num4 = length * (num2 / a);
            double x = System.Math.Round(num3 + center.x, 2);
            double y = System.Math.Round(num4 + center.y, 2);
            Console.WriteLine("该点的坐标是:<" + x + "," + y + ">");
            return new GePoint3d(x, y, 0);
        }

        /// <summary>
        /// 根据夹角和半径
        /// </summary> 
        /// <param name="pt1"></param>
        /// <param name="pt2"></param>
        /// <param name="pt3"></param>
        /// <param name="R"></param>
        /// <returns></returns>
        public static double getTByR(GePoint3d pt1, GePoint3d pt2, GePoint3d pt3, double R)
        {
            GeVec3d dv1 = GeVec3d.createByStartEnd(pt2, pt1);
            GeVec3d dv2 = GeVec3d.createByStartEnd(pt2, pt3);
            double dvAngel = dv1.getAngleTo(dv2);
            GeAngle angle = GeAngle.createByRadians(dvAngel / 2);

            //获取新得起终点 
            double T = Math.Abs(R * Math.Tan(Math.PI / 2 - angle.getRadians()));

            return T;
        }


        #region 获取1#钢筋距离放置点距离及放置排数
        /// <summary>
        /// 获取1#钢筋距离放置点距离及放置排数
        /// </summary>
        /// <param name="length"></param>
        /// <param name="edgeDistance"></param>
        /// <param name="n1"></param>
        /// <param name="n2"></param>
        /// <returns></returns>
        public static List<(double ditance, int num)> GetRebarNum1DistributeDistance(double length, double edgeDistance, int n1, int n2)
        {
            List<(double ditance, int num)> result = new List<(double ditance, int num)>();
            double total = (length - 2 * edgeDistance);
            double average = total / (n1 - 1);
            double edgeDistanceToUor = edgeDistance;
            var rebarNum1 = GetDistributeDistance(n1, n2);
            for (int i = 0; i < rebarNum1.Count; i++)
            {
                result.Add((edgeDistanceToUor + average * i, rebarNum1[i].locationNum));
            }
            return result;
        }

        /// <summary>
        /// 根据1#钢筋与1'#钢筋数量获取1#钢筋索引值及放置排数
        /// </summary>
        /// <param name="n1"></param>
        /// <param name="n2"></param>
        /// <returns>返回!#钢筋索引值及放置排数</returns>
        public static List<(int intdex, int locationNum)> GetDistributeDistance(int n1, int n2)
        {
            List<(int intdex, int locationNum)> result = new List<(int intdex, int locationNum)>();
            if (n1 < n2)
            {
                return null;
            }
            if (0 == n2)
            {
                for (int i = 0; i < n1; i++)
                {
                    result.Add((i, 1));
                }
            }
            else
            {
                var mid1 = n1 / 2;
                List<int> temp = new List<int>();//临时存储第二排钢筋位置
                for (int j = 0; j < n2; j++)
                {
                    if (j <= mid1)
                    {
                        temp.Add(j % 2 == 0 ? j : n1 - j);
                    }
                    else
                    {
                        temp.Add(n1 % 2 == 0 ? (j % 2 == 0 ? j - mid1 : n1 - j + mid1) : (j % 2 == 0 ? n1 - j + mid1 : j - mid1));
                    }
                }
                for (int i = 0; i < n1; i++)
                {
                    result.Add(temp.Contains(i) ? (i, 2) : (i, 1));
                }
            }
            return result;
        }
        #endregion

        #region 预制盖板计算2/3#钢筋的位置
        /// <summary>
        /// 预制盖板计算2/3#钢筋的位置
        /// </summary>
        /// <param name="length">盖板宽度</param>
        /// <param name="edgeDistance">主筋到盖板边缘距离</param>
        /// <param name="n1">2#钢筋数量</param>
        /// <param name="n2">3#钢筋数量</param>
        /// <param name="count">1号钢筋数量 (1#钢筋的位置是 2/3 摆放位置)</param>
        /// <returns>(每一根钢筋距离盖板边缘的距离, 放置钢筋的编号:2/3)</returns>
        public static List<(double ditance, int num)> GetRebarNo2No3DistributeDistance(double length, double edgeDistance, int n1, int n2, int count)
        {
            List<(double ditance, int num)> result = new List<(double ditance, int num)>();
            double total = (length - 2 * edgeDistance);
            double average = total / (count - 1);
            double edgeDistanceToUor = edgeDistance;
            var rebarNum1 = GetDistributeDistanceDifferentLocation(n1, n2, count);

            for (int i = 0; i < rebarNum1.Count; i++)
            {
                if (rebarNum1[i].locationNum == 0) continue;
                result.Add((edgeDistanceToUor + average * i, rebarNum1[i].locationNum));
            }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="n1">2#钢筋数量</param>
        /// <param name="n2">3#钢筋数量</param>
        /// <param name="count">1#钢筋数量</param>
        /// <returns>(第几个, 钢筋编号)</returns>
        public static List<(int intdex, int locationNum)> GetDistributeDistanceDifferentLocation(int n1, int n2, int count)
        {
            List<(int intdex, int locationNum)> result = new List<(int intdex, int locationNum)>();
            for (int i = 0; i < count; i++) result.Add((i, 0));

            List<int> no2Count = new List<int>();
            for (int i = 0; i < n1; i++)
                no2Count.Add(i);

            List<int> no3Count = new List<int>();
            for (int i = 0; i < n2; i++)
                no3Count.Add(i);

            var half = Math.Ceiling(count / 2.0);
            int falg = 0;
            int locationNum = 2;
            for (int i = 0; i < half; i++)
            {
                if (i % 2 == 0)
                {
                    if (falg % 2 == 0)
                    {
                        if (no2Count.Count > 0)
                        {
                            if (no2Count.Count >= 2)
                            {
                                result[i] = ((i, 2));
                                result[count - i - 1] = ((count - i - 1, 2));

                                no2Count.RemoveAt(0);
                                if (i != count - i - 1) no2Count.RemoveAt(0);
                            }
                            else if (no2Count.Count == 1)
                            {
                                result[i] = ((i, 2));
                                no2Count.RemoveAt(0);
                            }
                            locationNum = 2;
                        }
                        else
                        {
                            if (no3Count.Count >= 2)
                            {
                                result[i] = ((i, 3));
                                result[count - i - 1] = ((count - i - 1, 3));

                                no3Count.RemoveAt(0);
                                if (i != count - i - 1)
                                    no3Count.RemoveAt(0);
                            }
                            else if (no3Count.Count == 1)
                            {
                                result[i] = ((i, 3));
                                no3Count.RemoveAt(0);
                            }
                            locationNum = 3;
                        }
                    }
                    else if (falg % 2 == 1)
                    {
                        if (no3Count.Count > 0)
                        {
                            if (no3Count.Count >= 2)
                            {
                                result[i] = ((i, 3));
                                result[count - i - 1] = ((count - i - 1, 3));

                                no3Count.RemoveAt(0);
                                if (i != count - i - 1)
                                    no3Count.RemoveAt(0);
                            }
                            else if (no3Count.Count == 1)
                            {
                                result[i] = ((i, 3));
                                no3Count.RemoveAt(0);
                            }
                            locationNum = 3;
                        }
                        else
                        {
                            if (no2Count.Count >= 2)
                            {
                                result[i] = ((i, 2));
                                result[count - i - 1] = ((count - i - 1, 2));

                                no2Count.RemoveAt(0);
                                if (i != count - i - 1) no2Count.RemoveAt(0);
                            }
                            else if (no2Count.Count == 1)
                            {
                                result[i] = ((i, 2));
                                no2Count.RemoveAt(0);
                            }
                            locationNum = 2;
                        }

                    }
                    falg++;

                }
            }

            falg = 0;
            for (int i = 0; i < half; i++)
            {
                if (i % 2 == 1)
                {
                    if (locationNum == 3)
                    {
                        if (falg % 2 == 0)
                        {
                            if (no2Count.Count > 0)
                            {
                                if (no2Count.Count >= 2)
                                {
                                    result[i] = ((i, 2));
                                    result[count - i - 1] = ((count - i - 1, 2));

                                    no2Count.RemoveAt(0);
                                    if (i != count - i - 1) no2Count.RemoveAt(0);
                                }
                                else if (no2Count.Count == 1)
                                {
                                    result[i] = ((i, 2));
                                    no2Count.RemoveAt(0);
                                }
                            }
                            else
                            {
                                if (no3Count.Count >= 2)
                                {
                                    result[i] = ((i, 3));
                                    result[count - i - 1] = ((count - i - 1, 3));

                                    no3Count.RemoveAt(0);
                                    if (i != count - i - 1)
                                        no3Count.RemoveAt(0);
                                }
                                else if (no3Count.Count == 1)
                                {
                                    if (result[i].locationNum != 0)
                                    {
                                        result[count - i - 1] = ((count - i - 1, 3));
                                    }
                                    else
                                    {
                                        result[i] = ((i, 3));
                                    }
                                    no3Count.RemoveAt(0);

                                }
                            }
                        }
                        else if (falg % 2 == 1)
                        {
                            if (no3Count.Count > 0)
                            {
                                if (no3Count.Count >= 2)
                                {
                                    result[i] = ((i, 3));
                                    result[count - i - 1] = ((count - i - 1, 3));

                                    no3Count.RemoveAt(0);
                                    if (i != count - i - 1)
                                        no3Count.RemoveAt(0);
                                }
                                else if (no3Count.Count == 1)
                                {
                                    if (result[i].locationNum != 0)
                                    {
                                        result[count - i - 1] = ((count - i - 1, 3));
                                    }
                                    else
                                    {
                                        result[i] = ((i, 3));
                                    }
                                    no3Count.RemoveAt(0);
                                }
                            }
                            else if (no2Count.Count > 0)
                            {
                                if (no2Count.Count >= 2)
                                {
                                    result[i] = ((i, 2));
                                    result[count - i - 1] = ((count - i - 1, 2));

                                    no2Count.RemoveAt(0);
                                    if (i != count - i - 1) no2Count.RemoveAt(0);
                                }
                                else if (no2Count.Count == 1)
                                {
                                    result[i] = ((i, 2));
                                    no2Count.RemoveAt(0);
                                }
                            }
                        }
                    }
                    else
                    {
                        if (falg % 2 == 0)
                        {
                            if (no3Count.Count > 0)
                            {
                                if (no3Count.Count >= 2)
                                {
                                    result[i] = ((i, 3));
                                    result[count - i - 1] = ((count - i - 1, 3));

                                    no3Count.RemoveAt(0);
                                    if (i != count - i - 1)
                                        no3Count.RemoveAt(0);
                                }
                                else if (no3Count.Count == 1)
                                {
                                    result[i] = ((i, 3));
                                    no3Count.RemoveAt(0);
                                }
                            }
                            else if (no2Count.Count > 0)
                            {
                                if (no2Count.Count >= 2)
                                {
                                    result[i] = ((i, 2));
                                    result[count - i - 1] = ((count - i - 1, 2));

                                    no2Count.RemoveAt(0);
                                    if (i != count - i - 1) no2Count.RemoveAt(0);
                                }
                                else if (no2Count.Count == 1)
                                {
                                    if (result[i].locationNum != 0)
                                    {
                                        result[count - i - 1] = ((count - i - 1, 2));
                                    }
                                    else
                                        result[i] = ((i, 2));
                                    no2Count.RemoveAt(0);
                                }
                            }
                        }
                        else if (falg % 2 == 1)
                        {
                            if (no2Count.Count > 0)
                            {
                                if (no2Count.Count >= 2)
                                {
                                    result[i] = ((i, 2));
                                    result[count - i - 1] = ((count - i - 1, 2));

                                    no2Count.RemoveAt(0);
                                    if (i != count - i - 1) no2Count.RemoveAt(0);
                                }
                                else if (no2Count.Count == 1)
                                {
                                    if (result[i].locationNum != 0)
                                    {
                                        result[count - i - 1] = ((count - i - 1, 2));
                                    }
                                    else
                                        result[i] = ((i, 2));
                                    no2Count.RemoveAt(0);
                                }
                            }
                            else if (no3Count.Count > 0)
                            {
                                if (no3Count.Count >= 2)
                                {
                                    result[i] = ((i, 3));
                                    result[count - i - 1] = ((count - i - 1, 3));

                                    no3Count.RemoveAt(0);
                                    if (i != count - i - 1)
                                        no3Count.RemoveAt(0);
                                }
                                else if (no3Count.Count == 1)
                                {
                                    result[i] = ((i, 3));
                                    no3Count.RemoveAt(0);
                                }
                            }
                        }
                    }
                    falg++;
                }
                if (i != half - 1 || i != half - 2) continue;

                if (count % 2 == 1)
                {
                    if (i == half - 1)
                    {
                        for (int j = count - 1; j > 0; j--)
                        {
                            if (no2Count.Count == 1 && result[j].locationNum == 0) result[j] = ((j, 2));
                            if (no3Count.Count == 1 && result[j].locationNum == 0) result[j] = ((j, 3));
                            //if (no2Count.Count == 1) result[count - i - 1] = ((count - i - 1, 2));
                            //if (no3Count.Count == 1) result[count - i - 1] = ((count - i - 1, 3));
                        }

                    }

                }
                else
                {
                    if (i == half - 2)
                    {
                        if (no2Count.Count == 1) result[count - i - 2] = ((count - i - 2, 2));
                        if (no3Count.Count == 1) result[count - i - 2] = ((count - i - 2, 3));
                    }

                }
            }


            return result;
        }

        #endregion

        #region 现浇盖板获取所箍7号筋位置
        /// <summary>
        /// 现浇盖板获取所箍7号筋位置
        /// </summary>
        /// <param name="rebarRootNum1">每米1号筋个数</param>
        /// <param name="coverWidth">板宽</param>
        /// <param name="nextRowRebarRootNum">下排所箍根数</param>
        /// <param name="rebarNum">每排钢筋个数</param>
        /// <returns></returns>
        public static Dictionary<int, int> GetHopingLocation(double rebarRootNum1, double coverWidth, double nextRowRebarRootNum, double rebarNum)
        {
            Dictionary<int, int> result = new Dictionary<int, int>();

            var oneRebarSumNum = rebarRootNum1 * coverWidth;
            //所箍1号钢筋数
            var oneRebarNum = oneRebarSumNum - 2;
            //计算下排所箍数
            int hoopThatNum = (int)(nextRowRebarRootNum * coverWidth / 4);
            if (nextRowRebarRootNum < 4)
                hoopThatNum += 1;
            //空余钢筋数
            var unoccupiedRebarNum = oneRebarNum - (hoopThatNum * rebarNum);
            //平均箍筋间隔
            var interval = (int)(unoccupiedRebarNum / rebarNum) + 1;
            int left = 1;
            int right = (int)oneRebarSumNum - 2;
            for (int i = 0; i < rebarNum; i++)
            {
                if (i % 2 == 0)
                {
                    int tempIndex = left + hoopThatNum;
                    result.Add(tempIndex, left);
                    left = tempIndex + interval;
                }
                else
                {
                    int tempIndex = right - hoopThatNum;
                    result.Add(right, tempIndex);
                    right = tempIndex - interval;
                }
            }
            return result;
        }
        #endregion


        ///// <summary>
        ///// 缝合成体
        ///// </summary>
        ///// <param name="PtTops">顶面点集</param>
        ///// <param name="PtBottoms">底面点集</param>
        ///// <returns></returns>
        //public static BPGraphics seamSealer(List<GePoint3d> PtTops, List<GePoint3d> PtBottoms)
        //{
        //    List<GeCurveArray> curveArrays = new List<GeCurveArray>();
        //    PolyfaceHandlePtr polyHeader = PolyfaceHandle.createVariableSizeIndexed();
        //    //添加所有的顶点
        //    GePoint3dCollection pts_top = new GePoint3dCollection();
        //    for (int i = 0; i < PtTops.Count; i++)
        //    {
        //        pts_top.Add(PtTops[i]);
        //    }
        //    GePoint3dCollection pts_bottom = new GePoint3dCollection();
        //    for (int i = 0; i < PtBottoms.Count; i++)
        //    {
        //        pts_bottom.Add(PtBottoms[i]);
        //    }


        //    //构建顶面
        //    GeCurveArray curveArraytop = GeCurveArray.createLinestringArray(pts_top, BoundaryType.BOUNDARY_TYPE_Outer, true);
        //    curveArrays.Add(curveArraytop);

        //    //构建底面
        //    GeCurveArray curveArraybottom = GeCurveArray.createLinestringArray(pts_bottom, BoundaryType.BOUNDARY_TYPE_Outer, true);
        //    curveArrays.Add(curveArraybottom);

        //    //构建侧面
        //    for (int i = 0; i < pts_top.Count - 1; i++)
        //    {
        //        GePoint3dCollection pts = new GePoint3dCollection
        //        {
        //            pts_top[i],
        //            pts_top[i + 1],
        //            pts_bottom[i + 1],
        //            pts_bottom[i]
        //        };
        //        GeCurveArray curveArray = GeCurveArray.createLinestringArray(pts, BoundaryType.BOUNDARY_TYPE_Outer, true);
        //        curveArrays.Add(curveArray);
        //    }

        //    //构建侧面 尾_首
        //    GePoint3dCollection pts1 = new GePoint3dCollection
        //    {
        //        pts_top[pts_top.Count - 1],
        //        pts_top[0],
        //        pts_bottom[0],
        //        pts_bottom[pts_bottom.Count - 1]
        //    };
        //    GeCurveArray curveArray1 = GeCurveArray.createLinestringArray(pts1, BoundaryType.BOUNDARY_TYPE_Outer, true);
        //    curveArrays.Add(curveArray1);
        //    PolyfaceHandle polyface = BPMeshMeans.regionsGenerateMesh(curveArrays);
        //    BPGraphics bPGraphics = BPApplication.getInstance().getProjectManager().getActiveModel().createPhysicalGraphics();

        //    bPGraphics.addPolyface(polyface);

        //    //bPGraphics.save();

        //    return bPGraphics;
        //}

        public static GeRotMatrix CE单位矩阵(GePoint3d D矩阵原点, GePoint3d D矩阵X轴点, GePoint3d D矩阵Y轴点)
        {
            GeRotMatrix rMatrix = new GeRotMatrix();
            GeVec3d V矩阵原点 = GeVec3d.createByStartEnd(D矩阵原点, D矩阵原点);
            GeVec3d V矩阵X轴点 = GeVec3d.createByStartEnd(D矩阵原点, D矩阵X轴点);
            GeVec3d V矩阵Y轴点 = GeVec3d.createByStartEnd(D矩阵原点, D矩阵Y轴点);

            GeVec3d X轴单位向量 = new GeVec3d(0, 0, 0);
            GeVec3d Y轴单位向量 = new GeVec3d(0, 0, 0);
            GeVec3d Z轴单位向量 = new GeVec3d(0, 0, 0);
            GeVec3d Dnum = new GeVec3d(0, 0, 0);

            //X轴单位向量
            Dnum = V矩阵X轴点.minus(V矩阵原点);
            //单位向量
            Dnum.normalize();
            //MessageBox.Show(Convert.ToString(DVector3d.Zero.Distance(Dnum)));
            X轴单位向量 = Dnum;

            //Y轴单位向量
            Dnum = V矩阵Y轴点.minus(V矩阵原点);
            //单位向量
            Dnum.normalize();
            //MessageBox.Show(Convert.ToString(DVector3d.Zero.Distance(Dnum)));
            Y轴单位向量 = Dnum;

            //Z轴单位向量
            Dnum = X轴单位向量.cross(Y轴单位向量);
            //单位向量
            Dnum.normalize();
            //MessageBox.Show(Convert.ToString(DVector3d.Zero.Distance(Dnum)));
            Z轴单位向量 = Dnum;

            GeVec3d DVX = new GeVec3d(X轴单位向量.x, Y轴单位向量.x, Z轴单位向量.x);
            GeVec3d DVY = new GeVec3d(X轴单位向量.y, Y轴单位向量.y, Z轴单位向量.y);
            GeVec3d DVZ = new GeVec3d(X轴单位向量.z, Y轴单位向量.z, Z轴单位向量.z);

            rMatrix = GeRotMatrix.createByRowVectors(DVX, DVY, DVZ);

            return rMatrix;
        }

        /// <summary>
        /// 旋转(扭)洞口角度
        /// </summary>
        /// <param name="graphics">元素</param>
        /// <param name="angle">角度</param>
        /// <returns></returns>
        public static BPGraphics unitRotation(BPGraphics graphics, double angle)
        {
            //矩阵X,Y  圆锥不一致的半径 1:1000
            GePoint3d X = new GePoint3d(1, 0, 0);
            GePoint3d Y = new GePoint3d(Math.Tan(Math.PI * angle / 180), 1, 0);
            //矩阵变化
            GeRotMatrix rotMatrix = Helper.CE单位矩阵(GePoint3d.createByZero(), X, Y);
            GeTransform transform = GeTransform.create(rotMatrix, GePoint3d.createByZero());
            BPGraphicsUtils.transformPhysicalGraphics(graphics, transform);
            return graphics;

        }
    }
}
